#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>

#define NUM 1024

//定义缓冲类型
#define NONE_FLUSH 0x0
#define LINE_FLUSH 0x1
#define FULL_FLUSH 0x2

typedef struct _MyFILE 
{
    int _fileno;
    char _buffer[NUM]; //缓冲区
    int _end;
    int _flags; //标记刷新策略 fflush method
}MyFILE;

MyFILE *my_fopen(const char *filename,const char *method)
{
    assert(filename);
    assert(method);

    int flags = O_RDONLY;

    if(strcmp(method,"r")==0)
    {}
    else if(strcmp(method,"r+")==0)
    {}
    else if(strcmp(method,"w")==0)
    {
        flags = O_WRONLY | O_CREAT | O_TRUNC;
    }
    else if(strcmp(method,"w+")==0)
    {}
    else if(strcmp(method,"a")==0)
    {
        flags = O_WRONLY | O_CREAT | O_APPEND;
    }
    else if(strcmp(method,"a+")==0)
    {}

    int fileno = open(filename,flags,0666);
    if(fileno < 0)
        return NULL;

    MyFILE *fp = (MyFILE*)malloc(sizeof(MyFILE));
    if(fp == NULL)
        return fp;
    memset(fp,0,sizeof(MyFILE));

    fp->_fileno = fileno;
    fp->_flags |= LINE_FLUSH;
    fp->_end = 0;

    return fp;
}

void my_fflush(MyFILE *fp)
{
    assert(fp);
    if(fp->_end > 0)
    {
        write(fp->_fileno,fp->_buffer,fp->_end);
        fp->_end = 0;
        // 将内核中的数据刷新到磁盘里面
        syncfs(fp->_fileno);
    }
}

void my_fwrite(MyFILE *fp,const char *start,int len)
{
    assert(fp);
    assert(start);
    assert(len > 0);

    // 将数据写入缓冲区
    strncpy(fp->_buffer+fp->_end,start,len); 
    fp->_end += len;

    if(fp->_flags & NONE_FLUSH)
    {}
    else if(fp->_flags & LINE_FLUSH)
    {
        if(fp->_end > 0 && fp->_buffer[fp->_end-1] == '\n')
        {
            // 仅仅是写入到内核中
            write(fp->_fileno,fp->_buffer,fp->_end);
            fp->_end = 0;
            syncfs(fp->_fileno);
        }
    }
    else if(fp->_flags & FULL_FLUSH)
    {}
}

void my_fclose(MyFILE *fp)
{
    my_fflush(fp); 
    close(fp->_fileno);
    free(fp);
}

int main()
{
    MyFILE *fp = my_fopen("log.txt","w");
    if(fp == NULL)
    {
        printf("my_fopen error\n");
        return 1;
    }

    const char *s0 = "hello my file\n";
    my_fwrite(fp,s0,strlen(s0));
    printf("消息立即刷新\n");
    sleep(3);

    const char *s1 = "hello my file";
    my_fwrite(fp,s1,strlen(s1));
    printf("不满足刷新的字符串\n");
    sleep(3);

    const char *s2 = "hello my file";
    my_fwrite(fp,s2,strlen(s2));
    printf("不满足刷新的字符串\n");
    sleep(3);
    my_fclose(fp);

    const char *s3 = "hello my file";
    my_fwrite(fp,s3,strlen(s3));
    printf("满足刷新的字符串\n");
    sleep(3);

    const char *s4 = "hello my file";
    my_fwrite(fp,s4,strlen(s4));
    printf("不满足刷新的字符串\n");
    sleep(1);
    my_fflush(fp);
    sleep(3);
    return 0;
}
